﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////


#include "GnufExplorerBlockSorter.h"
#include "GnufModelViewBlock.h"
#include "GnufModelViewDefine.h"
#include "FamilyCmdAvailibilityUtils.h"
#include "GmViewType.h"
#include "GnufInfo.h"
#include "GnufTree.h"
#include "IDocument.h"
#include "IElementBasicInformation.h"
#include "IModelView.h"
#include "IUiDocument.h"
#include "InplaceEditModelViewProjectData.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

#define ICON_View_3D        L":/images/ModelView/View/3D"
#define ICON_View_Ceiling   L":/images/ModelView/View/Ceiling"
#define ICON_View_Elevation L":/images/ModelView/View/Elevation"
#define ICON_View_Plane     L":/images/ModelView/View/Plane"

using namespace gfam;
using namespace gcmp;
using namespace gnuf;

gnuf::TreeNode* gfam::ConcreteModelViewBlock::initBlockImpl(gnuf::TreeBoard* treeBoard)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(treeBoard != nullptr, L"treeBoard is nullptr", L"paramodel", L"2024-02-20");

    TreeNode* pNewNode = treeBoard->addTree();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pNewNode != nullptr, L"pNode is nullptr", L"paramodel", L"2024-02-20");

    pNewNode->setInfo(0, Info(getBlockName(), getBlockName(), getIcon()));
    pNewNode->setUserDataAt(TREE_USER_DATA_ROLE, getBlockName());

    return pNewNode;
}

void gfam::ConcreteModelViewBlock::refresh(gcmp::IUiDocument* pUiDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_parentNodeDelegate, L"m_parentNodeDelegate为空", L"paramodel", L"2024-02-20");
    TreeNode* pParentNode = m_parentNodeDelegate->getDelegatedNode();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParentNode != nullptr, L"pParentNode为空", L"paramodel", L"2024-02-20");

    if (FamilyCmdAvailibilityUtils::IsInProfileEditMode() && dynamic_cast<PlanModelViewBlock*>(this) == nullptr)
    {
        pParentNode->setEnable(false);
        return;
    }
    else
    {
        pParentNode->setEnable(true);
    }

    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc != nullptr, L"pUiDoc为空", L"paramodel", L"2024-02-20");

    IDocument* pDbDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDbDoc != nullptr, L"pDbDoc为空", L"paramodel", L"2024-02-20");

    m_pDoc = pDbDoc;
    std::vector<IModelView*> modelViews = IModelView::GetAllModelViews(pDbDoc);
    std::vector<IModelView*> source;
    FOR_EACH(view, modelViews)
    {
        std::vector<std::wstring> viewTypes = getViewTypes();
#pragma warning(push)
#pragma warning(disable: 4996)
        auto itr = std::find_if(viewTypes.begin(), viewTypes.end(), [&](const std::wstring& type)
            { return view->GetUserDataId().compare(type) == 0; });
#pragma warning(pop)
        if (itr != viewTypes.end()) source.push_back(view);
    }

    FOR_EACH(view, source)
    {
        // 过滤
        if (gcmp::InplaceEditModelViewProjectData::Get(view)) // 项目视图
        {
            if (false == m_IsProjectBlock) // 非项目Block
            {
                continue;
            }
        }
        else // 非项目视图
        {
            if (m_IsProjectBlock) // 项目Block
            {
                continue;
            }
        }

        DBG_WARN_AND_CONTINUE_UNLESS(view->GetBasicInformation(), L"view->GetBasicInformation() is nu:llptr", L"paramodel", L"2024-02-20");
        std::wstring strName = view->GetBasicInformation()->GetName();

        bool existed = false;
        ExplorerTreeNodeDelegate* pDelegate = m_parentNodeDelegate->addSubNode(strName, existed);
        DBG_WARN_AND_CONTINUE_UNLESS(pDelegate, L"pDelegate is nu:llptr", L"paramodel", L"2024-02-20");

        TreeNode* childItemView = pDelegate->getDelegatedNode();
        DBG_WARN_AND_CONTINUE_UNLESS(childItemView, L"childItemView is nullptr", L"paramodel", L"2024-02-20");

        if (!existed)
        {
            childItemView->enabledDrag(true);
            childItemView->setInfo(0, Info(strName, strName, L""));
            DBG_WARN_AND_RETURN_VOID_UNLESS(m_parentNodeDelegate->getDelegatedNode(), L"m_parentNodeDelegate->getDelegatedNode()为空", L"paramodel", L"2024-02-20");
            m_parentNodeDelegate->getDelegatedNode()->setExpanded(true);
        }
        childItemView->setUserDataAt(Gnuf_MODEL_VIEW_USER_DATA_ROLE, view->GetBasicInformation()->GetElementId().AsInt64());
        setExtraData(childItemView, view);
    }
}

std::vector<std::wstring> gfam::PlanModelViewBlock::getViewTypes() const
{
    return { PlanViewType, BMVI_BaseLevel };
}

std::wstring gfam::PlanModelViewBlock::getIcon() const
{
    return ICON_View_Plane;
}

gcmp::OwnerPtr<gnuf::TreeNodeSorter> gfam::PlanModelViewBlock::getSorter() const
{
    return NEW_AS_OWNER_PTR(ModelViewBlockSorter, m_pDoc, true);
}

std::vector<std::wstring> gfam::CeilingModelViewBlock::getViewTypes() const
{
    return{ CeilingViewType, BMVI_Ceiling };
}

std::wstring gfam::CeilingModelViewBlock::getIcon() const
{
    return ICON_View_Ceiling;
}

gcmp::OwnerPtr<gnuf::TreeNodeSorter> gfam::CeilingModelViewBlock::getSorter() const
{
    return NEW_AS_OWNER_PTR(ModelViewBlockSorter, m_pDoc, true);
}

std::vector<std::wstring> gfam::ElevationModelViewBlock::getViewTypes() const
{
    return{ ElevationViewType, BMVI_Right, BMVI_Left, BMVI_Front, BMVI_Back };
}

std::wstring gfam::ElevationModelViewBlock::getIcon() const
{
    return ICON_View_Elevation;
}

gcmp::OwnerPtr<gnuf::TreeNodeSorter> gfam::ElevationModelViewBlock::getSorter() const
{
    return NEW_AS_OWNER_PTR(ElevationModelViewBlockSorter);
}

void gfam::ElevationModelViewBlock::setExtraData(gnuf::TreeNode* pNode, gcmp::IModelView* pModelView)
{
    if (pNode != nullptr && pModelView != nullptr)
    {
        int sortIndicator;
        gcmp::Vector3d viewDir = pModelView->GetViewDirection();
        if (viewDir == Vector3d::NegaUnitX) sortIndicator = 0;
        else if (viewDir == Vector3d::UnitY) sortIndicator = 1;
        else if (viewDir == Vector3d::UnitX) sortIndicator = 2;
        else if (viewDir == Vector3d::NegaUnitY) sortIndicator = 3;

        pNode->setUserDataAt(Gnuf_ELEVATION_MODEL_VIEW_USER_DATA_ROLE, sortIndicator);
    }
}

std::vector<std::wstring> gfam::View3DModelViewBlock::getViewTypes() const
{
    return { View3DViewType, BMVI_3D };
}

std::wstring gfam::View3DModelViewBlock::getIcon() const
{
    return ICON_View_3D;
}

gcmp::OwnerPtr<gnuf::TreeNodeSorter> gfam::View3DModelViewBlock::getSorter() const
{
    return NEW_AS_OWNER_PTR(ModelViewBlockSorter, m_pDoc, false);
}